package com.gitee.wsgalaxy.gnodroid.connect;

import android.support.annotation.Nullable;
import android.util.Log;

import com.gitee.wsgalaxy.gnodroid.GndGlobal;

import java.nio.ByteBuffer;
import java.util.ArrayList;

/**
 * Created by wsgalaxy on 3/17/18.
 */

public class GndMessage {

    public ArrayList<GndMessageData> message_data_list = new ArrayList<GndMessageData>();

    public GndMessage()
    {}


    public boolean addData(GndMessageData data)
    {
        return message_data_list.add(data);
    }

    public boolean addData(byte[] bytes)
    {
        GndMessageData data = GndMessageData.generateMessageData(bytes);
        if (data == null) {
            return false;
        } else {
            return addData(data);
        }
        //return addData(GndMessageData.generateMessageData(bytes));
    }

    public byte[] generateBytes() throws Exception
    {
        int allDataSize = 0;
        int t1 = 0;
        for (GndMessageData d : message_data_list) {
            allDataSize += d.len;
            allDataSize += 4;
        }
        allDataSize = 8 + 4 + allDataSize + 8;
        byte[] bytes = new byte[allDataSize];
        int dataCount = message_data_list.size();

        System.arraycopy(GndGlobal.MESSAGE_TAG, 0, bytes, 0, 8);
        System.arraycopy(GndGlobal.MESSAGE_TAG, 0, bytes, allDataSize - 8, 8);

        //byte[] bytesT = "oxoxoxox".getBytes();

        int offset = 8;
        bytes[offset] = (byte) (dataCount >>> 24 & 0xff);
        bytes[offset + 1] = (byte) (dataCount >>> 16 & 0xff);
        bytes[offset + 2] = (byte) (dataCount >>> 8 & 0xff);
        bytes[offset + 3] = (byte) (dataCount & 0xff);
        offset += 4;

        for (GndMessageData d : message_data_list) {
            int dataLen = d.len;
            bytes[offset] = (byte) (dataLen >>> 24 & 0xff);
            bytes[offset + 1] = (byte) (dataLen >>> 16 & 0xff);
            bytes[offset + 2] = (byte) (dataLen >>> 8 & 0xff);
            bytes[offset + 3] = (byte) (dataLen & 0xff);
            offset += 4;
        }

        for (GndMessageData d : message_data_list) {
            System.arraycopy(d.data, 0, bytes, offset, d.len);
            offset += d.len;
        }

        if (offset + 8 != allDataSize) {
            return null;
        }

        return bytes;
    }

    public static GndMessage generateMessage(ByteBuffer byteBuffer)
    {
        byteBuffer.flip();
        int len = byteBuffer.remaining();
        if (len == 0) {
            return null;
        }
        byte[] bytes = new byte[len];
        try {
            byteBuffer.get(bytes);
        } catch (Exception e) {
            Log.d("gnd", e.getMessage());
            return null;
        }
        return generateMessage(bytes, len);
    }

    public static GndMessage generateMessage(byte[] bytes, int len)
    {
        if (!checkData(bytes, len)) {
            return null;
        }

        int offset = 8;
        int dataCount = (bytes[offset] << 24) +
                (bytes[offset + 1] << 16) +
                (bytes[offset + 2] << 8) +
                bytes[offset + 3];
        int[] dataLens = new int[dataCount];
        offset += 4;


        int allDataSize = 0;
        for (int t = 0; t < dataCount; t ++) {
            dataLens[t] = (bytes[offset] << 24) +
                    (bytes[offset + 1] << 16) +
                    (bytes[offset + 2] << 8) +
                    bytes[offset + 3];
            offset += 4;
            allDataSize += dataLens[t];
        }

        allDataSize = 8 + 4 + dataCount * 4 + allDataSize + 8;
        if (allDataSize != len) {
            return null;
        }

        GndMessage message = new GndMessage();
        GndMessageData toBeAdded = null;
        for (int t = 0; t < dataCount; t ++) {
            /*
            try {
                toBeAdded = new GndMessageData(bytes, offset, dataLens[t]);
                message.message_data_list.add(toBeAdded);
                offset += dataLens[t];
            } catch (Exception e) {
                return null;
            }
            */
            toBeAdded = GndMessageData.generateMessageData(bytes, offset, dataLens[t]);
            if (toBeAdded == null) {
                return null;
            }
            message.message_data_list.add(toBeAdded);
            offset += dataLens[t];
        }


        return message;
    }


    static boolean checkData(byte[] bytes, int len) {
        try {
            return (new String(bytes, 0, 8, "UTF-8"))
                    .equals(new String(bytes, len - 8, 8, "UTF-8"));

        } catch (Exception e) {
            Log.d("gnd", e.getMessage());
            return false;
        }
    }


    public static class GndMessageData{
        public int len = 0;
        public byte[] data = null;

        GndMessageData()
        {}

        /*
        public GndMessageData(byte[] bytes, int offset, int len) throws Exception
        {
            if (offset + len + 1 > bytes.length) {
                throw new Exception("too long");
            }

            this.len = len;
            data = new byte[this.len];
            System.arraycopy(bytes, offset, data, 0, len);
        }
        */

        @Nullable
        public static GndMessageData generateMessageData(byte[] bytes, int offset, int len)
        {
            if (offset + len > bytes.length) {
                return null;
            }

            GndMessageData data = new GndMessageData();
            data.len = len;
            data.data = new byte[data.len];
            System.arraycopy(bytes, offset, data.data, 0, data.len);
            return data;
        }

        public static GndMessageData generateMessageData(byte[] bytes)
        {
            return generateMessageData(bytes, 0, bytes.length);
        }
    }
}
